Home:ALL Converter>How to split F[A \/ B] into (F[A], F[B])

How to split F[A \/ B] into (F[A], F[B])

Ask Time:2013-05-29T22:24:29         Author:AlecZorab

Json Formatter

I occasionally hit code like this:

val things : List[A \/ B] = ???
val (as, bs) : (List[A], List[B]) = ??? //insert something to do this

or in my current case I want Map[A, B \/ C] => (Map[A, B], Map[A, C])

Is there a nice way to do this in the general case F[A \/ B] with appropriate restrictions on F? It looks vaguely like a variation on the theme of Unzip.

Author:AlecZorab,eproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/16816536/how-to-split-fa-b-into-fa-fb
stew :

Here's how we deal with this for / but also Either and Validation, and not just for Lists, but other Foldable.\n\nobject Uncozip {\n implicit val wtf = language.higherKinds\n\n // Typeclass which covers sum types such as \\/, Either, Validation\n trait Sum2[F[_, _]] {\n def cata[A, B, X](a: A ⇒ X, b: B ⇒ X)(fab: F[A, B]): X\n }\n\n implicit val sumEither: Sum2[Either] = new Sum2[Either] {\n def cata[A, B, X](a: A ⇒ X, b: B ⇒ X)(fab: Either[A, B]): X = {\n fab match {\n case Left(l) ⇒ a(l)\n case Right(r) ⇒ b(r)\n }\n }\n }\n\n implicit val sumEitherz: Sum2[\\/] = new Sum2[\\/] {\n def cata[A, B, X](a: A ⇒ X, b: B ⇒ X)(fab: A \\/ B): X = {\n fab.fold(a(_), b(_))\n }\n }\n\n implicit val sumValidation: Sum2[Validation] = new Sum2[Validation] {\n def cata[A, B, X](a: A ⇒ X, b: B ⇒ X)(fab: A Validation B): X = {\n fab.fold(a(_), b(_))\n }\n }\n\n abstract class Uncozips[F[_], G[_, _], A, B](fab: F[G[A, B]]) {\n def uncozip: (F[A], F[B])\n }\n\n implicit def uncozip[F[_]: Foldable, G[_, _], A, B](fab: F[G[A, B]])(implicit g: Sum2[G], mfa: ApplicativePlus[F], mfb: ApplicativePlus[F]): Uncozips[F, G, A, B] = new Uncozips[F, G, A, B](fab) {\n def uncozip = {\n implicitly[Foldable[F]].foldRight[G[A, B], (F[A], F[B])](fab, (mfa.empty, mfb.empty)) { (l, r) ⇒\n g.cata[A, B, (F[A], F[B])]({ (a: A) ⇒ (mfa.plus(mfa.point(a), r._1), r._2) },\n { (b: B) ⇒ (r._1, mfa.plus(mfa.point(b), r._2)) })(l)\n }\n }\n }\n}\n",
2013-05-29T14:54:08
mpilquist :

You can map things in to a list of (Option[A], Option[B]), unzip that list in to two lists, and then unite the resulting lists:\n\nimport scalaz._\nimport Scalaz._\n\nval things: List[String \\/ Int] = List(\"foo\".left, 42.right)\nval (strs, ints): (List[String], List[Int]) = things.\n map { d => (d.swap.toOption, d.toOption) }. // List[(Option[String], Option[Int])]\n unzip. // (List[Option[String]], List[Option[Int]])\n bimap(_.unite, _.unite) // (List[String], List[Int])\n\n\nThis isn't particularly efficient due to traversing the list three times.",
2013-05-29T14:44:04
yy